//! @file   lc_pair.h
//! @brief  
//! @author Sayan Chaliha
//! @date   October, 2011
//!
//! 
#ifndef _LC_PAIR_H
#define _LC_PAIR_H

#include "libcyan_internal.h"
#include "lc_types.h"

namespace cyan {
    template <typename A, typename B>
    class CYAN_API Pair {
    public:
        typedef A   FirstType;
        typedef B   SecondType;
        
        Pair() : first(), second() {
        }
        
        Pair(const FirstType& a, const SecondType& b) : first(a), second(b) {
        }
        
        template <typename U, typename V>
        Pair(const Pair<U, V>& pair) : first(pair.first), second(pair.second) {
        }
        
        template <typename U, typename V>
        typename EnableIf<AreComparable<FirstType, U>::value &&
                AreComparable<SecondType, V>::value, Bool>::Type
        operator ==(const Pair<U, V>& other) const {
            if (AreComparable<FirstType, U>::value &&
                AreComparable<SecondType, U>::value)
            return ((other.first == this->first) &&
                    (other.second == this->second));
        }
        
        template <typename U, typename V>
        typename EnableIf<AreComparable<FirstType, U>::value &&
                AreComparable<SecondType, V>::value, Bool>::Type
        operator !=(const Pair<U, V>& other) const {
            return ((other.first != this->first) ||
                    (other.second != this->second));
        }
        
        template <typename U, typename V>
        typename EnableIf<AreComparable<FirstType, U>::value &&
                AreComparable<SecondType, V>::value, Bool>::Type
        operator <(const Pair<U, V>& other) const {
            return ((this->first < other.first) ||
                    (this->second < other.second));
        }
        
        template <typename U, typename V>
        typename EnableIf<AreComparable<FirstType, U>::value &&
                AreComparable<SecondType, V>::value, Bool>::Type
        operator >(const Pair<U, V>& other) const {
            return ((this->first > other.first) ||
                    (this->second > other.second));
        }
        
        template <typename U, typename V>
        typename EnableIf<AreComparable<FirstType, U>::value &&
                AreComparable<SecondType, V>::value, Bool>::Type
        operator <=(const Pair<U, V>& other) const {
            return ((this->first <= other.first) ||
                    (this->second <= other.second));
        }
        
        template <typename U, typename V>
        typename EnableIf<AreComparable<FirstType, U>::value &&
            AreComparable<SecondType, V>::value, Bool>::Type
        operator >=(const Pair<U, V>& other) const {
            return ((this->first >= other.first) ||
                    (this->second >= other.second));
        }

        FirstType   first;
        SecondType  second;
    };
    
    template <typename U, typename V>
    Pair<U, V> makePair(U first, V second) {
        return Pair<U, V>(first, second);
    }
}

#endif /* _LC_PAIR_H */
